#include <bits/stdc++.h>

using namespace std;

const int infi = 255;
const int tot = 2000;

struct edge
{
	int to, next;
} e[tot * 9 + 1];

bool link[tot + 1][tot + 1];
int box[tot + 1];
int node_num, edge_num;

int f[tot + 1][tot + 1];
vector<vector<vector<unsigned char>>> dist;
queue<short> q[3];

void addedge(int s, int t)
{
	link[s][t] = true;
	edge_num++;
	e[edge_num].to = t;
	e[edge_num].next = box[s];
	box[s] = edge_num;
}

void make_graph()
{
	freopen("../datas/adj_matrix.txt", "r", stdin);
	for (int i = 1; i <= tot; i++)
	{
		for (int j = 1; j <= tot; j++)
			link[i][j] = false;
		box[i] = 0;
	}
	scanf("%d", &node_num);
	edge_num = 0;
	int max_cnt = 0, max_f = 0;
	for (int i = 1; i <= node_num; i++)
	{
		int cnt = 0;
		for (int j = 1; j <= node_num; j++)
		{
			int x;
			scanf("%d", &x);
			if (x == 1)
			{
				addedge(i, j);
				if (i == j)
					f[i][j] = 0;
				else
					f[i][j] = 1;
				cnt++;
			}
			else
				f[i][j] = infi;
		}
		max_cnt = max(max_cnt, cnt);
	}
	for (int k = 1; k <= node_num; k++)
		for (int i = 1; i <= node_num; i++)
			for (int j = 1; j <= node_num; j++)
				f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
	for (int i = 1; i <= node_num; i++)
		for (int j = 1; j <= node_num; j++)
			max_f = max(max_f, f[i][j]);
	printf("%d %d\n", max_cnt, max_f);
}

void init()
{
	for (int i = 0; i <= node_num; i++)
	{
		vector<vector<unsigned char>> l1;
		for (int j = 0; j <= node_num; j++)
		{
			vector<unsigned char> l2;
			for (int l = 0; l <= node_num; l++)
				l2.push_back(infi);
			l1.push_back(l2);
		}
		dist.push_back(l1);
	}
}

bool cond1(int i, int j, int l) { return link[i][l] || link[j][l]; }
bool cond2(int i, int j, int l) { return link[i][l] && link[j][l]; }

void calc()
{
	int head = 0, tail = -1;
	for (int i = 1; i <= node_num; i++)
		for (int j = 1; j <= node_num; j++)
			for (int l = 1; l <= node_num; l++)
			{
				if (cond1(i, j, l))
				{
					dist[i][j][l] = 0;
					tail++;
					q[0].push(l);
					q[1].push(i);
					q[2].push(j);
				}
			}
	while (head <= tail)
	{
		int t = q[0].front(), x = q[1].front(), y = q[2].front();
		q[0].pop(), q[1].pop(), q[2].pop();
		for (int l = box[t]; l; l = e[l].next)
		{
			bool ok = true;
			for (int i = box[e[l].to]; i; i = e[i].next)
				if (dist[x][y][t] < dist[x][y][e[i].to])
				{
					ok = false;
					break;
				}
			if (!ok)
				continue;
			for (int i = box[x]; i; i = e[i].next)
				for (int j = box[y]; j; j = e[j].next)
					if (dist[e[i].to][e[j].to][e[l].to] == infi)
					{
						dist[e[i].to][e[j].to][e[l].to] = dist[x][y][t] + 1;
						tail++;
						q[0].push(e[l].to);
						q[1].push(e[i].to);
						q[2].push(e[j].to);
					}
		}
		head++;
		if (head % (int)(1e7) == 0)
			printf("%d %d\n", head, dist[x][y][t]);
	}
	printf("%d %d ", tail + 1, node_num * node_num * node_num);
	if (tail + 1 == node_num * node_num * node_num)
		printf("ok\n");
	else
		printf("not ok\n");

	// Write binary data to file
	FILE *outfile = fopen("../datas/D_bin.txt", "wb");
	if (outfile)
	{
		for (int i = 0; i <= node_num; i++)
			for (int j = 0; j <= node_num; j++)
				for (int l = 0; l <= node_num; l++)
					fputc(dist[i][j][l], outfile);
		fclose(outfile);
	}
}
int main()
{
	make_graph();
	init();
	calc();
	return 0;
}
